<?php
namespace PI;



class Module{
    public $application;

    public $requestMethod;
    //模块所在目录
    public $dir;  
    //模块的全名，就是该模块的namespace名，用\开头
    public $fullname;
    //模块的classname
    public $classname;
    //模块的文件名，如果未定义module，就是null
    public $filename;

    //当前加载的控制器类名
    public $controllerClassname;
    public $controllerName;
    public $controllerFilename;
    public $controller;
    
    public $actionName;
    public $actionResult;

    public $viewFilename;
    public $viewClassname;
    public $view;

    //默认的控制器名称，不是fullname
    public $defaultController;
    //默认的action名
    public $defaultAction;

    public $caches;

    public $routes;

    public $routeDatas;

    function __construct(){
        //var_dump($_SERVER);
        $this->caches = [];
        $this->configure();
    }

    protected function configure(){

    }

    function dispose():Module{
        if($this->caches){
            foreach($this->caches as $inst){
                if($inst===$this) continue;
                if(method_exists($inst,"dispose")){
                    $inst->dispose();
                }
            }
        }
        return $this;
    }

    public function get_cache($name){
        if(isset($this->caches[$name])){
            $val = $this->caches[$name];
            return $val;
        }
        if($this!==$this->application){
            return $this->application->get_cache($name);
        }
        return null;
    }
    

    protected function request(array &$paths):bool{
        //从路由中弹出第一个参数,当作控制器名
        $controllerName = array_shift($paths);
        //试图创建控制器实例
        $controller = $controllerName?$this->create_controller($controllerName):null;
        //未能创建控制器,这个$controllerName可能不是控制器名，使用默认控制器
        if($controller===null){
            //当前取出来的不是控制名，放回$paths
            if($controllerName)array_unshift($paths,$controllerName);
            //把取出来的控制名清空，后面如果action无法执行，会把控制器名压回去，这里已经压回去了，清空指示不要做压回去的操作
            $controllerName=null;
            //使用默认的控制器名
            $default_controllerName = $this->defaultController;
            //本模块的默认控制器名未定义，用application的默认配置;如果自己就是application，就不找了
            if(!$default_controllerName && $this->application !==$this) $controllerName = $this->application->defaultController;
            //一直找不到控制器名，这个模块没有处理该请求，返回false
            if(!$default_controllerName) return false; 
            //找到了控制名，试图加载默认的控制器
            $controller = $this->create_controller($default_controllerName);
            //默认控制也未能加载，返回false
            if(!$controller) return false;
            
        }
        //注入一些参数
        if($this->controller instanceof Controller){
            $this->controller->__module__= $this;
        }
        
        //action并未执行
        if(!$this->do_action($paths)){
            if($controllerName!==null) array_unshift($controllerName);
            //返回false,未能处理
            return false;
        }
        return true;
    }

    protected function create_controller($controllerName){
        //获取请求的控制的类名
        $controllerClassname = $this->fullname."\\$controllerName"."Controller";
        if(class_exists($controllerClassname)){
            $this->controllerClassname = $controllerClassname;
            //如果缓存中有，直接返回该控制器的实例
            $cached = $this->get_cache($controllerName);
            if( $cached!==null)return $cached;
            //类存在，但没有缓存过
        }else {
            throw new \Exception("无法加载控制器$controllerName,模块:$this->dir");
            
        }
        $this->controllerClassname = $controllerClassname;

        //以依赖注入方式创建类实例
        $controller = $this->controller  = $this->application->create_instance($controllerClassname,true);
        $this->controllerName = $controllerName;
        return $controller;
    }

    protected function do_action(array &$paths){
        //弹以恶出来当作action_name
        $actionName = array_shift($paths);
        //没找到方法，不是action_name
        if(!$actionName || !method_exists($this->controller,$actionName)){
            //压回去，还原路由数据
            if($actionName)array_unshift($paths,$actionName);
            //获取default_action
            $actionName = $this->defaultAction;
            if(!$actionName && $this!==$this->application) $actionName = $this->application->defaultAction;
            //没找到default_action 该模块没有处理请求，返回false
            if(!$actionName) return false;
            //还是没找到方法，该模块不会处理请求，返回false
            if(!method_exists($this->controller,$actionName)) return false;
        }
        //找到了方法，更新状态
        $this->actionName = $actionName;

        $this->routeDatas = $this->build_routeData($this->controller,$actionName,$paths);

        //调用方法
        $actionResult =$this->actionResult =  $this->invoke_action($this->controller,$actionName,null,$this->routeDatas);
        $this->response($actionResult);
        return true;
    }

    


    protected function response(&$actionResult){
        if($actionResult instanceof ActionResult){
            $actionResult->render();
        }
        if($this->requestAccept==="json"){
            echo json_encode($actionResult);
            return $this;
        }
        if(is_object($actionResult) && method_exists($actionResult,"render")){
            echo $actionResult->render();
            return $this;
        }
        
        $view_file = "$this->module_dir/_views/$this->controllerName"."_$this->actionName.view.php";
        
        if(file_exists($view_file)){
            $this->viewFilename= $view_file;
            global $_VIEWSTATES;
            $_VIEWSTATES = $actionResult;
            require_once($view_file);
            $view_name = $this->module_fullname."\\$this->controllerName"."_$this->actionName"."View";
            if(function_exists($view_name)){
                $this->view_fullname = $view_name;
                $view_name($actionResult);
            }else if (class_exists($view_name)){
                $this->view_fullname = $view_name;
                $view = $this->view = new $view_name();
                $view->render($actionResult);
            }
        }else {
            echo is_string($actionResult)?$actionResult:json_encode($actionResult);
        }
        
        return $this;
    } 

    function invoke_action($inst,string $actionName,$args=null,array $routeData=null){
        //if(is_string($inst)) $inst = $this->create_instance($inst,"controller");
        if(!method_exists($inst,$actionName)){
            throw new \Exception("控制器".get_class($inst)."上没有$actionName 方法");
        }
        if($args!==null){
            return call_user_func_array([$inst,$actionName],$args);
        }

        
        $methodInfo = new \ReflectionMethod(get_class($inst), $actionName);
        $paramInfos = $methodInfo->getParameters();
        $paramCount = count($paramInfos);
        if($paramCount===0){
            return call_user_func([$inst,$actionName]);
        }
        $jsonDatas=null;
        if($this->requestContentType==="json"){
            $jsonText = file_get_contents('php://input');
            $jsonDatas = json_decode($jsonText,true);
            
        }
        $datas= $_REQUEST;

        $args = [];
        $argIndex= 0;
        foreach($paramInfos as $paramInfo){
            if(0==$argIndex++){
                $parCls = $paramInfo->getClass();
                if($parCls!==null){
                    $parClsname = $parCls->getName();
                    $value = $this->create_viewModel($parClsname,$inst,$actionName);
                    $props = get_class_vars($parClsname);
                    if($jsonDatas!=null){
                        foreach($props as $pname){
                            if(isset($jsonDatas[$pname])) $value->$pname= $jsonDatas[$pname];
                        }
                    }else {
                        foreach($props as $pname){
                            if(isset($routeData[$pname])) $value->$pname= $routeData[$pname];
                            else if(isset($datas[$pname])) $value->$pname = $datas[$pname];
                        }
                    }
                    $args[]=$value;
                    continue;
                }
                
            }
            $pname = $paramInfo->getName();
            if(isset($routeData[$pname]))  $args[] = $routeData[$pname];
            else if($jsonDatas && isset($jsonDatas[$pname]))  $args[] = $jsonDatas[$pname];
            else if(isset($datas[$pname])) $args[] = $datas[$pname];
            else if($paramInfo->isDefaultValueAvailable()){
                $args[] = $paramInfo->getDefaultValue();
            }else $args[]= null;
        }
        return call_user_func_array([$inst,$actionName],$args);
    }   


    function create_viewModel($modelFullname,$controller ,$actionName){
        return new $modelFullname();
    }

    function get_routeRule($controller , $actionName){
        $routes = isset($controller::$routes)?$controller::$routes:null;
        $rule = null;
        if($routes!==null){
            if(isset($routes[$actionName])) $rule = $routes[$actionName];
            if($rule===null && isset($routes[""])) $rule = $routes[""];  
        }
        if($rule!==null) return $rule;

        $routes = $this->routes;
        if($routes!==null){
            if(isset($routes[$actionName])) $rule = $routes[$actionName];
            if($rule===null && isset($routes[""])) $rule = $routes[""];  
        }
        if($rule!==null) return $rule;

        if($this->application===$this)return null;

        $routes = $this->application->$routes;
        if($routes!==null){
            if(isset($routes[$actionName])) $rule = $routes[$actionName];
            if($rule===null && isset($routes[""])) $rule = $routes[""];  
        }
        return $rule;

    }

    function build_routeData($controller,$actionName, array $paths):array{
        $rule = $this->get_routeRule($controller,$actionName);
        $routeData= [];
        if($rule){
            $index = 0;
            foreach($rule as $name) $routeData[$name] = $paths[$index++];
        }
        return $routeData;
    }

}

class Application extends Module{
    public $dir;
    public $requestMethod;
    public $requestContentType;
    public $requestAccept;

    public $paths;

    public $defaultController;
    public $defaultAction;
    public $defaultModule;

    public $routes;
    public $vars;

    public $module;

    //public $caches;
    
    public $caches;

    public $specialTypes;

    public function __construct(&$vars=null){
       global $PI;
       $PI = $this;
        $this->vars = &$vars;
        if($vars){
            if(isset($vars["defaultController"])) $this->defaultController = $vars["defaultController"];
            if(isset($vars["defaultModule"])) $this->defaultModule = $vars["defaultModule"]; 
            if(isset($vars["defaultAction"])) $this->defaultAction = $vars["defaultAction"]; 
            if(isset($vars["routes"])) $this->routes = $vars["routes"]; 
        }
        
        $this->specialTypes= ["Controller","View","Service","Model,Entity"];
        if($vars && isset($vars["specialTypes"])){
            $this->specialTypes = array_merge($this->specialTypes,$vars["specialTypes"]);
        }
        
        
        $this->fullname = "";
        $this->filename = __FILE__;
        $this->classname = "\\".__CLASS__;
        $this->application = $this;
        $this->init_https($vars);
        parent::__construct();
        //if($cfgs && !$cfgs["manual_start"]) $this->run();
    }

    protected function init_https(&$vars){
        $fname = $_SERVER["SCRIPT_FILENAME"];
        $at = strrpos($fname,"/");
        if($at!==false){
            $this->dir = substr($fname,0,$at);
        }else $this->dir = $fname;
        $this->module_dir = $this->dir;
        if(isset($_SERVER["PATH_INFO"])){
            $this->paths = explode("/",trim($_SERVER["PATH_INFO"],"/"));
        }else $this->paths=[];
        

        $content_type = isset($_SERVER["HTTP_CONTENT_TYPE"])?$_SERVER["HTTP_CONTENT_TYPE"]:null;
        if($content_type&& strpos($content_type,"/json")!==false){
            $this->requestContentType = "json";
        }

        $accept = isset($_SERVER["HTTP_ACCEPT"])?$_SERVER["HTTP_ACCEPT"]:null;
        if($accept){
            if(strpos($accept,"/json")!==false){
                $this->requestAccept = "json";
            } else if(strpos($accept,"/text")!==false){
                $this->requestAccept = "text";
            }
                
        }
        $this->requestMethod = isset($_SERVER["REQUEST_METHOD"])?$_SERVER["REQUEST_METHOD"]:null;
    }

    protected function configure(){
        $vars = &$this->vars;
        $this->caches=[""=>$this,"\\PI\Application"=>$this];
        if(!$vars) return $this;
        if(!isset($vars["injections"])) return $this;
        $injections = $vars["injections"];
        foreach($injections as $k=>$v){
            if(substr($k,0,1)==="\\"){
                if(is_string($v)){
                    throw new \Exception("not implement,配置中injections节，类名作为key ,无法处理值是字符串的情况");
                }else if($v instanceof \Closure){
                    $this->caches[$k] = $v();
                }
            }else $this->caches[$k] = $v;
        }
    }

    static function run($vars=null){
        global $_PI;
        $_PI = new Application($vars);
        $_PI->process()->dispose();
    }

    

    function process():Application{
        $module = $this->load_module();
        //第一次加载的模块未处理请求，转到默认模块去处理
        if(!$module->request($this->paths) && $this->default_module！==null && $this->defaultModule!==$module->fullname){
            $defaultModule = $this->defaultModule;
            if(($defaultModule===""  || $defaultModule==="\\") ) {
                if( $module != $this){
                    $req_result = $this->request($this->paths);
                }
            }else {
                $additions = explode("\\",trim($defaultModule,"\\"));
                $this->paths = array_merge($additions,$this->paths);
                $module = $this->load_module();
                $req_result = $module->request($this->paths);
            }
            if(!$req_result) throw new \Exception("不正确的路径信息，无法找到相应的模块/控制器/方法");

        }
        return $this;
    }

    protected function load_module():Module{
        $paths = &$this->paths;
        // 1 controller/action/xxx
        $modules = [];
        $module_dir = $this->dir;
        
        while($pathname=array_shift($paths)){
            $tmp_dir= $module_dir."/".$pathname;
            if(is_dir($tmp_dir)) {
                $modules[] = $pathname;
                $module_dir = $tmp_dir;
                continue;
            }else {
                array_unshift($paths,$pathname);
                break;
            }
        }
        

        if($modules){   
            $module_name = array_pop($modules);
            array_push($modules,$module_name);
            $module_fullname = "\\".implode("\\",$modules);
            $module_clsname = $module_fullname."\\$module_name"."Module";
            $cached_module = $this->get_cache($module_clsname);
            if($cached_module ) {
                $module =$cached_module ;
            }else {
                $module_dir = $this->dir."/".implode("/",$modules);
                $module_filename = "$module_dir/$module_name.module.php";
                if(file_exists($module_filename)){
                    require_once($module_filename);
                    if(class_exists($module_clsname)){
                        $module = $this->create_instance($module_class_name,false,true);
                    }else {
                        throw new \Exception("未能再$module_filename 中找到类 $module_clsname");
                    }
                }else{
                    $module_filename = null;
                    //该目录至少要有一个_controllers,否则什么都处理不了
                    if(!is_dir($module_dir."/_controllers")){
                        return false;
                    }
                    $module = new Module();
                    $module_clsname = "\\PI\\Module";
                }
            } 
        }else{
            $module=$this;
        }
        if($module!==$this){
            $module->requestMethod = $this->requestMethod;
            $module->application = $this;
            $module->dir = $module_dir;
            $module->fullname = $module_fullname;
            $module->filename = $module_filename;
            $module->classname = $module_clsname;
        }
        $this->module = $module;
        
        return $module;
    }

    

    function create_instance(string $clsname,bool $useCache=false){
        if(substr($clsname,0,1)!="\\") $clsname = "\\".$clsname;
        if($useCache){
            $cached = $this->get_cache($clsname);
            if($cached) return $cached;
        } 
        
        
        // 通过反射获取反射类
        $clsInfo = new \ReflectionClass($clsname);

        // 查看是否可以实例化
        if (! $clsInfo->isInstantiable())
        {
            throw new \Exception($clsname . ' 类不可实例化');
        }

        // 查看是否用构造函数
        $ctorInfo = $clsInfo->getConstructor();

        // 没有构造函数的话，就可以直接 new 本类型了
        if (is_null($ctorInfo)){
            $inst= new $clsname();
            if($useCache){
                $this->caches[$clsname] = $inst;
                if($this!==$this->application){
                    if(!isset($this->application->caches[$clsname])) $this->application->caches[$clsname]= $inst;
                }
            }
            return $inst;
        }

        // 有构造函数的话就获取构造函数的参数
        $parameterInfos = $ctorInfo->getParameters();
        if(count($parameterInfos)==0){
            $inst= new $clsname();
            if($useCache){
                $this->caches[$clsname] = $inst;
                if($this!==$this->application){
                    if(!isset($this->application->caches[$clsname])) $this->application->caches[$clsname]= $inst;
                }
            }
            return $inst;
        }

        // 处理依赖关系
        $actual_parameters = [];

        foreach ($parameterInfos as $paramInfo)
        {
            // 获取对象名字，如果不是对象返回 null
            $parCls = $paramInfo->getClass();
            if($parCls!==null){
                $parClsname = $parCls->getName();
                $cachedValue = $this->get_cache($parClsname);
                if($cachedValue!==null){
                    $actual_parameters[] = $cachedValue;
                }else {
                    $parValue = $this->create_instance($parCls->getName(),true,true);
                    $actual_parameters[] = $parValue;
                }
                continue;
            }
            // 获取变量的名字
            $var_name = $paramInfo->getName();
            $cachedValue = $this->get_cache($var_name);
            // 如果是对象， 则递归new
            if ($cachedValue!==null)$actual_parameters[] =$cachedValue;
            else{
                if (! $paramInfo->isDefaultValueAvailable()) throw new \Exception($clsname."的构造函数中".$var_name . ' 参数没有默认值');
                $actual_parameters[] = $paramInfo->getDefaultValue();
                
            }

        }


        // 获得构造函数的数组之后就可以实例化了
        $inst = $clsInfo->newInstanceArgs($actual_parameters);
        if($useCache){
            $this->caches[$clsname] = $inst;
            if($this!==$this->application){
                if(!isset($this->application->caches[$clsname])) $this->application->caches[$clsname]= $inst;
            }

        }
        return $inst;
    }

    function __GET($name){
        $_cfgs = $this->vars;
        if(!$_cfgs) return null;
        return isset($_cfgs[$name])?$_cfgs[$name]:null;
    }

    function __SET(string $name,$value){
        if($this->vars===null) $this->vars=[];
        $this->vars[$name] = $value;
    }
    
}
global $PI;

spl_autoload_register(function ($class) {
    global $PI;
    $fullname = "/".trim(str_replace("\\","/",$class),"/");
    $filename = null;
    
    
    foreach($PI->specialTypes as $type){
        if(preg_match('/'.$type.'$/',$fullname)){
            
            $at = strrpos("/",$fullname);
            $basPath = substr($fullname,0,$at);
            $shortName = substr($fullname,$at+1);
            $type = lcfirst($type);
            if($type==="controller"){
                $filename.="$basPath/".substr($shortName,0,strlen($shortName)-strlen($type)).".controller.php";
            }else {
                $filename.="$basPath/_".$type."/".substr($shortName,0,strlen($shortName)-strlen($type)).".$type.php";
            }
            
            break;
        }
    }
    if(!$filename) $filename = $fullname.".class.php";
    $filename = $PI->dir."/$filename";
    if(file_exists($filename)) require_once($filename);
});

class ActionResult{
    public $details ;
    public $controller;
    function __construct($data,$controller){
        $this->details = $data;   
        $this->controller = $controller;
    }
    function render(){

    }
}
class TextResult extends ActionResult{
    function __construct($data,$controller){
        parent::__construct($data,$controller);
    }

    function render(){
        echo $this->data;
    }
}
class JsonResult extends ActionResult{
    function __construct($data,$controller){
        parent::__construct($data,$controller);
    }

    function render(){
        echo json_encode($this->data);
    }
}

class RedirectResult  extends ActionResult{
    function __construct($data,$controller){
        parent::__construct($data,$controller);
    }

    function render(){
        header("Location: $this->data");
    }
}

class ViewResult  extends ActionResult{
    public $view_name;
    function __construct($controller,$data,string $viewname=null){
        parent::__construct($data,$controller);
        $this->view_name = $viewname;
    }

    function render(){
        header("Location: $this->data");
    }
}

class ErrorResult extends ActionResult{
    public $error;
    public $message;
    function __construct($controller, string $no,string $message=null,$details=null){
        parent::__construct($details,$controller);
        $this->error = $no;
        $this->message = $message;
    }

    function render(){
        header("Location: $this->data");
    }
}

class ViewModel implements \JsonSerializable,\ArrayAccess{
    public $error_no;
    public $response_message;
    public $info_details;
    protected $_attrs;

    function set_id($id){
        throw new \Exception("Abstract method");
    }
    function validate(array $allows=null,array $denies=null):bool{
        return true;
    }

    function jsonSerialize(){
        if(!$this->_attrs) return $this;
        $vars = get_object_vars($this);
        $attrs = &$this->_attrs;
        foreach($vars as $pname=>$pvalue){
            if($pname=="_attrs") continue;
            $attrs[$pname] = $pvalue;
        }
        return $attrs;
    }

    function offsetExists($offset){
        return $this->_attrs && isset($this->_attrs);
    }

    function offsetGet($offset){
        return $this->_attrs && isset($this->_attrs[$offset])?$this->_attrs[$offset]:null;
    }

    function offsetSet($offset, $value){
        if($this->_attrs===null) $this->_attrs = [];
        $this->_attrs[$offset] = $value;
    }

    function offsetUnset($offset){
        if($this->_attrs) unset($this->_attrs[$offset]);
    }

    function __get(string $name){
        if(!$this->_attrs) return null;
        return isset($this->_attrs[$name]) ? $this->_attrs[$name]:null;
    }

    function __set(string $name,$value){
        if(!$this->_attrs===null) $this->_attrs=[];
        $this->_attrs[$name] = $value;
    }
}

class View{
    function render($states){

    }

    function render_field($states,$name,$type,$label,$inputName,$info){
        if(!$inputName) $inputName = $name;
        if(!$label) $label = $name;
        $invalids = $states->details;
        $rule = isset($invalids[$inputName])?$invalids[$inputName]:null;
        $required = "";
        if($info)  $required = $info->required?"<ins class='required'>*<ins>":"";
 ?>
        <div class="field <?=$type?> <?=$name?> <?= $rule?"error":"" ?>">
            <label class='field-label'><span><?=$label ?><?=$required?></label>
            <?php $this->render_input($states,$type,$inputName,$info)?>
            <?php if($info) $this->render_validations($info,$rule?$rule->name:null)?>
        </div>
 <?php       
    }
    function render_input($states,$type,$inputName,$info){
        $invalids = $states->details;
        $rule = isset($invalids[$inputName])?$invalids[$inputName]:null;
        $errMessage = $rule? $this->get_validationText($rule,$info):"";
        $errMessage = preg_replace('/[<>]/',"",str_replace("\"","'",$errMessage));
        ?>
            <input class='field-input' type="<?=$type?>"  name="<?=$inputName?>" value="<?= $states->$inputName ?>" />
    <?php }

    function render_validations($info,string $invalidName=null){
        if($info) return;
        $rules = is_object($info)?$info->rules:(isset($info["rules"])?$info["rules"]:null);
        if(!$rules) return;
        echo "\t\t\t\t<ul class='field-validations'>";
        foreach($rules as $rule){
            $txt = $this->get_validationText($rule);
            if(!$txt) continue;
            $hasError = $rule->name ===$invalidName?"invalid":"";
            echo "\t\t\t\t\t<li class='$hasError'>$txt</li>\n";
        }

        echo "\t\t\t\t</ul>";
    }

    function get_validationText(ValidateRule $rule,$info=null){
        if($rule->name==="required") return "必填";
        else if($rule->name==="length") {
            if(is_numeric($rule->args)) return "最多$rule->args个字符";
            else if(is_array($rule->args)) return "字符个数为$rule->args[0]"."-$rule->args[1]";
            else return "输入的字符个数超出系统限制";
        }else if($rule->name==="range") {
            return "取值范围为:$rule->args[0]"."~$rule->args[1]";
        }else if($rule->name==="regx") {
            $txt = "";
            if($info)$txt = is_object($info)?$info->formatDescription:(isset($info["formatDescription"])?$info["formatDescription"]:null);
            if(!$txt) $txt = isset(Validations::$messages["regx"])?Validations::$messages["regx"]:"特定格式";
            if(!$txt) $txt= "特定格式";
        }
        $msg = isset(Validations::$messages[$rule->type])?validations::$messages[$rule->type]:null;
        if($msg) return $msg;
    }
}


class Controller{
    static $routes;
    public $user;
    public $__module__;
    function redirect(string $url){ return new RedirectResult($url,$this);}

    function text(string $text){ return new TextResult($text,$this);}

    function json($obj){return new JsonResult($obj,$this);}

    function view($obj,string $viewname=null){ return new ViewResult($this,$obj,$viewname);}

    function error(string $no,string $message=null,$details=null){return new ErrorResult($this,$no,$message,$details);}

}


final class Validations{
    static $validators=[];
    static $messages=[];
    static function register(string $name,$check){
        static::$validators[$name] = $check;
    }

    function validate(string $name, $args , $value):ValidateRule{
        $validator = isset(static::$validators[$name])?static::$validators[$name]:null;
        if(!$validator) return true;
        if(!$validator($value,$args)){
            return new ValidateRule($name,$args);
        }return true;
    }
}
Validations::register("required",function($value,$args){
    if($args==="strict"){
        if(is_string($value)) $value = trim($value);
        if(!$value)return false;
    }else if($args==="week"){
        return $args!==null;
    }else {
        if(is_array($value)) return true;
        else if(is_numeric($value)) return true;
        else if($value) return true;
        else return false;
    }
});
Validations::register("required",function($value,$args){
    if($args==="strict"){
        if(is_string($value)) $value = trim($value);
        if(!$value)return false;
    }else {
        return $args!==null;
    }
});
Validations::register("min_length",function($value,$args){
    $len = strlen($value);
    return $len>=$args;
});
Validations::register("max_length",function($value,$args){
    $len = strlen($value);
    return $len<=$args;
});
Validations::register("length",function($value,$args){
    $len = strlen($value);
    if(is_array($args)){
        $min = $args[0];
        $max = $args[1];
        return ($len>=$min && $len<=$max);
    }else {
        return $len<=$args;
    }
});
Validations::register("min",function($value,$args){
    return $value>=$args;
});
Validations::register("max",function($value,$args){
    return $value<=$args;
});
Validations::register("range",function($value,$args){
    $min = $args[0];
    $max = $args[1];
    return ($value>=$min && $value<=$max);
});
Validations::register("regx",function($value,$args){
    return preg_match($args,$value)>0;
});
$checkInteger= function($value,$args){
    if($args) {
        $value = strval($args);
        $value = preg_replace("/(\\s|,)+/i","",$value);
    }
    return preg_match("/^\\s*(\\+\\-)?\\d+\\s*$/ig",$value)>0;
};
Validations::register("int",$checkInteger);
Validations::register("integer",$checkInteger);
Validations::register("uint",function($value,$args){
    if($args) {
        $value = strval($args);
        $value = preg_replace("/(\\s|,)+/i","",$value);
    }
    return preg_match("/^\\s*\\d+\\s*$/ig",$value)>0;
});
$checkNumeric = function($value,$args){
    if($args) {
        $value = strval($args);
        $value = preg_replace("/(\\s|,)+/i","",$value);
    }
    return preg_match("/^\\s*(\\+\\-)?\\d+(.\\d+)?\\s*$/ig",$value)>0;
};
Validations::register("numeric",$checkNumeric);
Validations::register("float",$checkNumeric);
Validations::register("double",$checkNumeric);
Validations::register("decimal",$checkNumeric);

class ValidateRule{
    public $name;
    public $args;
    function __construct($name,$args=null){
        $this->name = $name;
        $this->args = $args;
    }
}
